package com.lsec.springbootinit.aop;

import com.lsec.springbootinit.utils.JsonUtils;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.CodeSignature;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.time.LocalDateTime;
import java.util.*;

/**
 * @author: Cherry
 * @create: 2022-08-25 18:57
 * @description:  统一日志切面
 */

@Slf4j
@Aspect
@Component
@Profile({"dev","stating"})
public class WebLogAspect {

    /**
     * 换行符
     */
    private static final String LINE_SEPARATOR = System.lineSeparator();

    ThreadLocal<Long> startTime = new ThreadLocal<>();

    @Pointcut("execution(public * com.lsec.springbootinit.controller..*.*(..))")
    public void exectionMethod(){}


    @Before("exectionMethod()")
    public void doBefore(JoinPoint joinPoint){

        // 开始打印请求日志
        // 开始时间
        startTime.set(System.currentTimeMillis());
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        String method = request.getMethod();
        // 打印请求相关参数
        log.info("=========================== Start ===========================");
        // 打印请求 url
        log.info("URL            : {}", request.getRequestURL().toString());
        // 打印 Http method
        log.info("HTTP Method    : {}", method);
        // 打印调用 controller 的全路径以及执行方法
        log.info("Class Method   : {}.{}", joinPoint.getSignature().getDeclaringTypeName(), joinPoint.getSignature().getName());
        // 打印请求的 IP
        log.info("IP             : {}", request.getRemoteAddr());
        // 打印请求入参
        log.info("Request Args   : {}", "GET".equals(method) ? getParams(joinPoint) : JsonUtils.getBeanToJson(joinPoint.getArgs()));


    }

    public static void main(String[] args) {
        System.out.println("LocalDateTime.now() = " + LocalDateTime.now());
    }


    @AfterReturning(pointcut="exectionMethod()",returning = "object")
    public Object doAfter(Object object){

        String responseContent = object != null ? JsonUtils.getBeanToJson(object) : "";
        // 打印出参
        log.info("Response Args  : {}", responseContent);
        // 执行耗时
        log.info("Time-Consuming : {} ms", System.currentTimeMillis() - startTime.get());
        log.info("=========================== End =============================" + LINE_SEPARATOR);
        return object;
    }


    /**
     * 获取参数Map集合
     * @param joinPoint
     * @return
     */
    private String getParams(JoinPoint joinPoint) {
        Map<String, Object> param = new HashMap<>();
        Object[] paramValues = joinPoint.getArgs();
        String[] paramNames = ((CodeSignature)joinPoint.getSignature()).getParameterNames();
        for (int i = 0; i < paramNames.length; i++) {
            param.put(paramNames[i], paramValues[i]);
        }
        return paramToString(param);
    }



    /**
     * 将Map中的非空的value拼接为json字符串
     * @param paramMap
     * @return
     */
    public String paramToString(Map<String, Object> paramMap) {
        String json;
        StringBuilder stringBuffer = new StringBuilder();
        //json字符串的第一个位置应该是 {
        stringBuffer.append("{");
        //去除Map中的所有Key值，放入Set集合中
        Set<String> paramKey = paramMap.keySet();
        //遍历出每一个key值，然后取出Map中的对应value做非空判断，若非空就进行拼接到stringBuffer中
        for (String param : paramKey) {
            if (paramMap.get(param) != null) {
                stringBuffer.append("\"").append(param).append("\":\"").append(paramMap.get(param).toString().trim()).append("\",");
            }
        }
        //若stringBuffer的长度大于2，则表示Map中有非空value并拼接到stringBuffer，那么就要去掉stringBuffer最后位置的逗号，然后再拼接上}即可；
        //若stringBuffer的长度小于2，则表示Map中没有非空value拼接到stringBuffer,那么只需给stringBuffer再拼接上}即可
        if (stringBuffer.length() > 2) {
            String substring = stringBuffer.substring(0, stringBuffer.length() - 1);
            json = substring + "}";
        } else {
            json = stringBuffer + "}";
        }
        return json;
    }


}
